package Mode;

/**
 * 单例模式:只能创建一个实例对象
 *
 * 两种实现方式:
 * 1. 饿汉模式
 *      一下子干完所有事(急)
 * 2. 懒汉模式(高效, 但要考虑多线程)
 *      用多少干多少
 *
 * 类对象: .class文件, 类对象中有类的所有信息(包括private), 在Java中只能有一个类对象
 *
 * 最重要的三点:
 * 1.正确位置加锁
 * 2.双重if判断
 * 3.volatile
 */


//饿汉模式(线程安全)
class Singleton{
    //饿汉就立即创建
    private static Singleton instance = new Singleton();//类方法
    //防止new对象,把构造方法设置为private
    private Singleton(){}
    //提供一个方法来获得实例
    public static Singleton getInstance(){
        //仅仅读取了变量的内容
        return instance;
    }
}

//懒汉模式
class Singleton1{
    //懒汉等需要再创建
    private static Singleton1 instance;//类方法
    //防止new对象,把构造方法设置为private
    private Singleton1(){}
    //提供一个方法来获得实例
    public static Singleton1 getInstance(){
        if (instance == null){
            //这里修改了,而且读和写不是原子的
            //多个线程调用这个方法就有可能会导致创建多个实例
            instance = new Singleton1();
        }
        return instance;
    }
}

/*
    来实现一个线程安全的懒汉模式
 */

class Singleton2{
    private static volatile Singleton2 instance;//类方法
    private Singleton2(){}
    public static Singleton2 getInstance(){
        //加锁,将读和写放在一起
        if (instance == null){//这里是因为如果创建实例成功后,只剩下读操作(线程安全了),但是锁仍然在,所以这里设置如果没有创建线程再进来
            //所以直接给方法加锁是一个无脑加锁,有可能会拖慢程序运行
            synchronized (Singleton.class){//让类对象为锁对象
                if (instance == null){
                    instance = new Singleton2();
                }
            }
        }
        return instance;
    }
}

/*
    但是还有一个问题:如果太多线程去读instance这个变量, 就难免编译器优化去寄存器中读(内存可见性问题)
    所以还要给instance加上一个volatile就能避免问题(如上)
 */

public class Test1 {}